package org.elasticsearch.plugin.index.query.cnn;

import org.apache.lucene.index.AtomicReader;
import org.apache.lucene.index.BinaryDocValues;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.Scorer;
import org.apache.lucene.search.Weight;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.ElasticsearchCNNProcessException;
import org.elasticsearch.plugin.util.SerializationUtils;

import java.io.IOException;

/**
 * Calculate score for each image
 * score = (1 / distance) * boost
 */
public abstract class AbstractCNNScorer extends Scorer {
    private final String luceneFieldName;
    private final IndexReader reader;
    private final float boost;
    private BinaryDocValues binaryDocValues;
    private double[] data;

    protected AbstractCNNScorer(Weight weight, String luceneFieldName, double[] data, IndexReader reader,
                                  float boost) {
        super(weight);
        this.luceneFieldName = luceneFieldName;
        this.reader = reader;
        this.boost = boost;
        this.data = data;
    }

    @Override
    public float score() throws IOException {
        assert docID() != NO_MORE_DOCS;

        if (binaryDocValues == null) {
            AtomicReader atomicReader = (AtomicReader) reader;
            binaryDocValues = atomicReader.getBinaryDocValues(luceneFieldName);
        }

        try {
            BytesRef bytesRef = binaryDocValues.get(docID());
            //String s = new String(bytesRef.bytes);
            /*if(s.contains("-0.0-0.0")){
            	System.out.println("FOUND\n" + s);
            }*/
            double[] docData = SerializationUtils.toDoubleArray(bytesRef.bytes);
            
            float distance = (float)SerializationUtils.distance(docData, data);
            float score;
            if (Float.compare(distance, 1.0f) <= 0) { // distance less than 1, consider as same image
                score = 2f - distance;
            } else {
                score = 1 / distance;
            }
            return score * boost;
        } catch (Exception e) {
            throw new ElasticsearchCNNProcessException("Failed to calculate score", e);
        }
    }

    @Override
    public int freq() {
        return 1;
    }
}
